package com.dj.common.web.exception;

import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.slf4j.Logger;

abstract public class BaseErrorCodes {

	/**
	 * 存放错误代码的列表
	 */
	private final static List<String> errorCodes = new LinkedList<>();

	/**
	 * key是错误代码的前缀，值是类名的一个映射，如{restful.json=com.dj.controller.rest.service.impl.RestFulJsonImpl$ErrorCodes}
	 */
	final static private Map<String, String> loadedErrorCodes = new TreeMap<>();

	final static private String replacingPattern = String.format("%s|%s|%s", "(?<=[A-Z])(?=[A-Z][a-z])",
			"(?<=[^A-Z])(?=[A-Z])", "(?<=[A-Za-z])(?=[^A-Za-z])");

	protected Logger logger = org.slf4j.LoggerFactory.getLogger(getClass());

	protected BaseErrorCodes() {
		String prefix = getErrorCodePrefix();
		String className = getClass().getName();
		String loadedClassName = loadedErrorCodes.get(prefix);
		if (loadedClassName != null && !loadedClassName.equals(className)) {
			throw new RuntimeException(
					String.format("Trying to load error code prefix %s from %s, which is already defined %s", prefix,
							className, loadedClassName));
		} 
		
		loadedErrorCodes.put(prefix, className);
		logger.info("Error code class already loaded: " + className);
		
		for (Field f : getClass().getFields()) {
			String errorCode = getErrorCodeFromFieldName(f);
			try {
				f.set(this, errorCode);
			} catch (Exception e) {
				throw new RuntimeException(String.format("Failed to set value %s on %s.%s", errorCode,
						getClass().getSimpleName(), f.getName()));
			}
			errorCodes.add(errorCode);
		}
	}

	/**
	 * 
	 * @return 错误代码的前缀
	 */
	protected abstract String getErrorCodePrefix();

	public static Collection<String> getAllErrorCodes() {
		return Collections.unmodifiableCollection(errorCodes);
	}

	private String getErrorCodeFromFieldName(Field field) {
		String ec = String.format("%s.%s", getErrorCodePrefix(),
				field.getName().replaceAll(replacingPattern, ".").toLowerCase());
		return fixErrorCode(ec);
	}

	private String fixErrorCode(String ec) {
		while (ec.contains("..")) {
			ec = ec.replace("..", ".");
		}
		return ec;
	}
}
